home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / dos / streams / handles / handles.doc < prev    next >
Encoding:
Text File  |  1992-04-01  |  12.6 KB  |  271 lines

  1.  
  2.      ********* Some notes about handles in MSDOS and Turbo C *********
  3.  
  4. NOTE: Borland changed the code for handling files in BCC++ 3.0, in a small
  5. but significant way. Some of the comments below about the way in which
  6. Turbo C handles files do not apply to BCC++ 3.0. See the file "bcc30.doc"
  7. for further comments.
  8.  
  9. (1) MSDOS maintains a table of information about open files. The number
  10. of entries in this table is set in config.sys by the FILES=nn statement.
  11. Programs do not refer to this table directly but via a tag called a handle.
  12. Handles are numbers 0,1,2,...,etc. The number of handles which a program
  13. can have is limited not just by the number determined by the FILES=nn
  14. statement but also by the size of a handle table of which each program
  15. has its own version. By default the handle table is in the PSP of the
  16. program and can hold 20 entries. Any program can request that it be granted
  17. a larger table (for DOS versions >= 3.3) by making a call to MSDOS via
  18. int 0x21, function 0x67.
  19.  
  20. (2) So far, so good. One of the unfortunate features of MSDOS programs
  21. is that text files usually use CR-LF character pairs to indicate line
  22. endings rather than just LF as used in UNIX and C. The MSDOS file system
  23. cares nothing about this and does not provide any particular support for
  24. either system.
  25.  
  26. (3) Turbo C provides support for both systems. In Turbo C, files may
  27. be either "text" or "binary" files. "Text" files are the special case;
  28. for files which are opened as "text" files, Turbo C automatically
  29. translates between the LF which "C" uses and CR-LF character pairs in
  30. the actual file on disk (or a device).
  31.  
  32. (4) To support this, EVERY file which Turbo C accesses via its library
  33. functions (read(), fread(), etc) must be have an associated piece of
  34. information which says whether it is "text" or "binary". Turbo C keeps
  35. this information in a table called _openfd.
  36.  
  37. (5) None of this would necessarily cause any real problems. The problem
  38. arises because Turbo C uses the DOS file handle as both the "int handle"
  39. used by its functions AND as the index into the _openfd table. The
  40. relevant part of _open() function of Turbo C is basically:
  41.         int  _openfd[20];
  42.         int _open(char *name, int mode)
  43.         {
  44.         int handle;
  45.         handle = dos_open(name, mode);     /* int 21h, function 3dh */
  46.         _openfd[handle] = mode;
  47.         return handle;
  48.         }
  49. Note that the code does not check whether the handle returned by MSDOS
  50. is < 20. This will cause no problems to programs which use the default
  51. handle table but if a program is granted a larger handle table then
  52. handles with values larger than 19 may be returned and the above code
  53. will write beyond the boundaries of the _openfd[] array.
  54.  
  55. (6) Although the Turbo C _open() function does not check the handle,
  56. the close() function does! You may open() a file which returns a handle
  57. of value 20 or larger but you can't close() it!
  58.  
  59. (7) The _openfd array is in a module called FILES2. This is the only
  60. contents of that module. Therefore the limitation of the size of the
  61. _openfd array is easily overcome by having a larger array of the
  62. same name defined in some module which is loaded before the Turbo C
  63. libraries. Unfortunately this does not overcome the problem with
  64. close(). However, the close() function is quite simple and writing
  65. a suitable replacement for it is easy.
  66.  
  67. (8) I have written some suitable code for Turbo C which appears in the
  68. file "close.c". See the file "readme" for details on how to use this code.
  69.  
  70. (9) There is a price to pay for having an increased number of handles.
  71. The price is:
  72.     (a) in MSDOS: each file appears to require 59 bytes in the internal
  73.         table of MSDOS. On my system, using MSDOS 5.00, an extra 11808
  74.         bytes of memory were used by the resident portion of MSDOS when
  75.         I increased files=55 to files=255.
  76.     (b) the handle table: when a handle table larger than 20 handles is
  77.         requested, MSDOS shifts the handle table out of the PSP. If the
  78.         requested size is N bytes then the new handle table will occupy
  79.         an extra N (rounded up to the nearest multiple of 16) bytes.
  80.     (c) the _openfd[] array: each extra handle increases the size of this
  81.         array by two bytes.
  82.     (d) a few bytes for the increase_handles() function and the call to
  83.         it (about 43+3 = 46 bytes in the small model).
  84.  
  85.  
  86.  
  87.  
  88. ************ Dangerous curves here (TeX jargon: means beware!) **************
  89.  
  90. Here is some inside information which I have deduced from observing
  91. the behaviour of MSDOS 5.00:
  92.  
  93. For files, there are two tables of interest which I call the
  94. file_struct_table and the file_table (I don't have a set of MicroSoft
  95. documentation so I don't know the "official" names, or even if such names
  96. exist).
  97.  
  98. The file_struct_table is internal to MSDOS and has nn entries where nn is
  99. from the files=nn statement in config.sys.
  100.  
  101. The file_table is for internal use by MSDOS but exists in the memory
  102. space of your program (in the PSP by default).
  103.  
  104.  
  105.     file_struct_table                   file_table
  106.      +-------------+               +-----------------+
  107.      | entry #0    |          +--- | entry #0        | <----- (handle)
  108.      +-------------+          |    +-----------------+
  109.      | entry #1    | <--------+    | entry #1        |
  110.      +-------------+               +-----------------+
  111.      .             .               .                 .
  112.      .             .               .                 .
  113.      +-------------+               +-----------------+
  114.      | entry #nn-1 |               | entry #MAX_FD-1 |
  115.      +-------------+               +-----------------+
  116.      each ~ 59 bytes                   each = 1 byte
  117.  
  118.  
  119. Each file_table entry is one byte in size and contains an unsigned
  120. number in the range [0..255]. The value 255 means that that file_table
  121. entry is invalid. All other values are pointers to the file_struct_table.
  122. A file_table entry with value n points to entry #n of the file_struct_table.
  123. Therefore the file_struct_table is limited in size to 255 usable entries
  124. (entry #0 to entry #254).
  125.  
  126. Entry #0, #1, and #2 of the file_struct_table appear to be special and refer
  127. to the serial device (AUX), console (CON), and printer (PRN) respectively.
  128. The first five entries of the file_table a program are therefore normally:
  129.             (handle)   (file)   (value)    (purpose)
  130.                0        CON        1       stdin
  131.                1        CON        1       stdout
  132.                2        CON        1       stderr
  133.                3        AUX        0       stdaux
  134.                4        PRN        2       stdprn
  135. If re-direction is used then these will be modified. For example a program
  136. test2.exe run with     test2 >blogs   will start with a file_table:
  137.             (handle)   (file)   (value)    (purpose)
  138.                0        CON        1       stdin
  139.                1        BLOGS      3       stdout
  140.                2        CON        1       stderr
  141.                3        AUX        0       stdaux
  142.                4        PRN        2       stdprn
  143.  
  144. Now for the interesting part...
  145.  
  146. Notice that five entries of the file_table may be used to refer to just
  147. three entries of the file_struct_table.
  148.  
  149. Every time a program opens another file, both an unused entry in the
  150. file_struct_table and an unused entry in the file_table are allocated
  151. (even if the same file is opened over and over..). If files=255 is specified
  152. in config.sys then there are up to 255-3 = 252 entries available in the
  153. file_struct_table for use in response to requests to open files. This then
  154. implies that the file_table can be up to 252+5=257 entries long.
  155.  
  156. What is a handle? A handle is just an entry number of (i.e. an index into)
  157. the file_table. Since the file_table can have up to 257 entries, a handle
  158. can have values in the range [0..256]. The important point here is that if
  159. you want to use the maximum possible number of file handles then IT IS
  160. INVALID TO USE A BYTE TO STORE A FILE HANDLE, a larger unit of storage is
  161. required e.g. a short or int in "C".
  162.  
  163. If you want to be able to have the maximum possible number of file handles
  164. under MSDOS 3.1 (3.0 ?) or greater then:
  165.         (a)   put         files=255               in config.sys
  166.         (b)   use         #define MAX_FD 257      in close.c
  167. This will allow a program access to 255-3 = 252 simultaneously open files.
  168. (Note: To use DOS service 0x67 you need DOS 3.3 or greater).
  169.  
  170.  
  171. Notes:
  172. (1) Entries 0, 1, and 2 need not actually exist in the file_struct_table
  173.     since they refer to devices rather than files (I don't know how this
  174.     table is constructed internally to MSDOS).
  175.  
  176.  
  177.  
  178. ******** Double dangerous curves here (TeX jargon: means BEWARE!) ***********
  179.  
  180. It is possible to use int 0x21, service 0x67 to get more file handles,
  181. but with certain restrictions.
  182.  
  183. When a program is loaded by MSDOS, it gets two blocks of memory:
  184.  
  185.          block 1    +--------------+
  186.                     | environment  |
  187.                     +--------------+
  188.  
  189.          block 2    +--------------+ lower memory addresses
  190.                     | program code |
  191.                     | and data     |
  192.                     |              |
  193.                     +--------------+ higher memory addresses
  194.  
  195. then when a request is made to MSDOS via service 0x67 for more than
  196. 20 handles, and extra block of memory is allocated for the new table,
  197. usually just above block 2:
  198.  
  199.          block 1    +--------------+
  200.                     | environment  |
  201.                     +--------------+
  202.  
  203.          block 2    +--------------+ lower memory addresses
  204.                     | program code |
  205.                     | and data     |
  206.                     |              |
  207.                     +--------------+ higher memory addresses
  208.          block 3    +--------------+
  209.                     | new handle   |
  210.                     | table        |
  211.                     +--------------+
  212.  
  213. This should not necessarily cause any problems.
  214.  
  215. But with Turbo C, it does! All turbo C models except the TINY model
  216. give access to the far heap (which is the same as the ordinary heap
  217. in the COMPACT, LARGE, and HUGE models). Turbo C allocates memory on
  218. the far heap by requesting MSDOS to increase the size of its code/data
  219. memory block (block 2). If block 3 has already been allocated as above
  220. then there is no room to increase the size of block 2, hence the
  221. request must fail. Once MSDOS service 0x67 has allocated block 3 then
  222. subsequent memory allocation calls in Turbo C which require extra
  223. space on the far heap will fail. This includes calls to fopen() in
  224. the large-data models; fopen() calls setvbuf() which in turn calls
  225. malloc().
  226.  
  227. Therefore to use service 0x67 it will often be necessary to make
  228. DOS put the new handle table as high in memory as possible. Two ways
  229. of doing this suggest themselves:
  230. (i) Request DOS to increase the size of the block of memory which is
  231. allocated to the program, then use service 0x67, and finally request
  232. DOS to reduce the program's memory back to its original size. This is
  233. a little messy, but it will work.
  234. (ii) Request DOS to use the LAST FIT memory allocation strategy, then
  235. use service 0x67. DOS will then place the handle table as high in
  236. DOS memory as is possible. DOS should then be requested to use the
  237. original memory allocation strategy again. Code to perform this
  238. is included as an alternative in the file "close.c".
  239.  
  240. There are potential problems with the use of schemes which put the
  241. handle table high in DOS memory. Firstly, it can result in some memory
  242. fragmentation if a high-loading tsr is loaded by a program which uses
  243. such a scheme. Secondly, it is more likely to cause obscure bugs or
  244. system crashes due to programs (or tsrs) which have previously undetected
  245. bugs in the way in which they use memory.
  246.  
  247. Perhaps better solution is to not use MSDOS service 0x67 at all. It
  248. is fairly easy to perform the functions of this service but use
  249. space obtained from Turbo C for the handle table. In this way the
  250. extra block (block 3) is never created for the program. This is the
  251. default method used in "close.c".
  252.  
  253. There is no problem with using MSDOS service 0x67 under the default
  254. FIRST FIT memory allocation strategy in Turbo C programs which do not
  255. access the far heap. This includes go32.exe of DJGPP.
  256.  
  257.  
  258. ***************** Triple dangerous curves here. *******************
  259.  
  260. It appears that some extensions to MS-DOS (such as network drivers)
  261. make use of files (or file handles?) which have the ms bit (bit 7) set.
  262. On systems which have such extensions installed, it may be prudent to
  263. not set the files=nn statement to greater than 127.
  264.  
  265.  
  266. -------------
  267. 30th March 1992
  268.  
  269. W. Metzenthen
  270. apm233m@vaxc.cc.monash.edu.au
  271.